﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Net;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;

namespace Engine.NetClasses
{
    [Serializable()]
    public class ServerOptions
    {
       
        #region Fields		
        /// <summary>
        /// Максимальное число подключений
        /// по умолчанию 100
        /// </summary>
        private int m_maxConnection = 100;
        /// <summary>
        /// Серверный протокол
        /// </summary>
        private int m_protocol = 713;
        /// <summary>
        /// Время интервала пинга
        /// </summary>
        private int m_pingTime = 60000;
        /// <summary>
        /// Базовая папка опций
        /// </summary>
        [field: NonSerialized()]
        private static string _ServerOptionFolder = "Options/";
        /// <summary>
        /// Имя файла опций по умолчанию
        /// </summary>
        [field: NonSerialized()]
        public static string _ServerOptionFile = "GlobalOption.bin";
        /// <summary>
        /// Файл Списка Серверов
        /// </summary>
        [field: NonSerialized()]
        private static string _ServerListFile = "ServerList.ini";
        /// <summary>
        /// Базовая папка лога
        /// </summary>
        private string _baseLogDir = "Logs/";
        /// <summary>
        /// Папка лога
        /// Статуса сервера
        /// </summary>
        private string _StateLogDir = "State/";
        /// <summary>
        /// Папка лога
        /// Запросы к серверу сервера
        /// </summary>
        private string _ReqestLogDir = "Receive/";
        /// <summary>
        /// Папка лога
        /// Отправка клиенту
        /// </summary>
        private string _SendLogDir = "Send/";
        /// <summary>
        /// Размер буфера
        /// </summary>
        private int m_receiveBufferSize = 2048;// buffer size to use for each socket I/O operation
        /// <summary>
        /// AddressFamily
        /// 0-"ipv4" ,1-"ipv6"
        /// </summary>
        private string[] addressFamily = new string[] { "ipv4", "ipv6" };
        /// <summary>
        /// Текуший используемый тип AddressFamily
        /// </summary>
        private byte m_currentAddressFamily = 0;
        /// <summary>
        /// Порт сервера
        /// </summary>
        private int m_port = 7777;
        /// <summary>
        /// Признак будут ли с этого сервера 
        /// получать список других серверов
        /// </summary>       
        private bool m_isRedirect = false;
        /// <summary>
        /// Если m_isRedirect=true
        /// Надо загрузить Список серверов
        /// из файла ServerList.ini
        /// </summary>
        [field: NonSerialized()]
        private ServersList[] m_serverList = null;
        /// <summary>
        /// Признак что изменили настройки и надо сохранить
        /// </summary>
        private bool m_change = false;
        /// <summary>
        /// Нестандартное название
        /// файла настроек
        /// </summary>
        private string m_offerOptionFile = null; 
	#endregion
        #region Propertes
        public string OfferOptionFile { get { return m_offerOptionFile; } set { m_offerOptionFile = value; } }
        public bool ChangeOption { set { m_change = value; } }
        public string AddressFamilyCurrent
        {
            get { return addressFamily[m_currentAddressFamily]; }
            set
            {
                // This sample supports two address family types: ipv4 and ipv6 
                if (value.Equals("ipv4"))
                {
                    m_currentAddressFamily = 0;
                }
                else if (value.Equals("ipv6"))
                {
                    m_currentAddressFamily = 1;
                }
                else
                {
                    throw new ArgumentException("Invalid address family specified");
                }

            }
        }
        public string[] AddressFamilyList
        {
            get { return addressFamily; }
            set { addressFamily = value; }
        }
        public IPEndPoint IPEndPoint
        {
            get
            {
                IPEndPoint localEndPoint;
                // This sample supports two address family types: ipv4 and ipv6 
                if (addressFamily[m_currentAddressFamily].Equals("ipv4"))
                {
                    localEndPoint = new IPEndPoint(IPAddress.Any, m_port);
                }
                else if (addressFamily[m_currentAddressFamily].Equals("ipv6"))
                {
                    localEndPoint = new IPEndPoint(IPAddress.IPv6Any, m_port);
                }
                else
                {
                    throw new ArgumentException("Invalid address family specified");
                }
                return localEndPoint;
            }
        }
        public int Port
        {
            get { return m_port; }
            set { m_port = value; }
        }
        public bool IsRedirect { get { return m_isRedirect; } set { m_isRedirect = value; } }
        public int MaxConnection { get { return m_maxConnection; } set { m_maxConnection = value; } }
        public int Protocol { get { return m_protocol; } set { m_protocol = value; } }
        public int ReciveBufferSize { get { return m_receiveBufferSize; } set { m_receiveBufferSize = value; } }
        public string BaseLogDir { get { return _baseLogDir; } set { _baseLogDir = value; } }
        public string StateLogDir { get { return _StateLogDir; } set { _StateLogDir = value; } }
        public string ReceiveLogDir { get { return _ReqestLogDir; } set { _ReqestLogDir = value; } }
        public string SendLogDir { get { return _SendLogDir; } set { _SendLogDir = value; } }
        public ServersList[] ServerList { get { return m_serverList; } set { m_serverList = value; } }
        public string ServerListFile { get { return _ServerListFile; } }
        public string ServerOptionFile
        {
            get
            {
                if (m_offerOptionFile == null)
                {
                    return m_offerOptionFile;
                }
                else
                {
                    return _ServerOptionFile;
                }

            }
        }
        public string ServerOptionFolder { get { return _ServerOptionFolder; } }
        public int PingTime
        {
            get { return m_pingTime; }
            set { m_pingTime = value; }
        }
        #endregion
        #region Constructor
         public ServerOptions()
        {
            if (!File.Exists(_ServerOptionFolder + _ServerOptionFile))
            {
                Init();
                ShowForm();
            }

        }
        #endregion
        #region Methods

         public void Init()
         {
             if (!Directory.Exists(_ServerOptionFolder))
             {
                 Directory.CreateDirectory(_ServerOptionFolder);
             }
             if (!Directory.Exists(_baseLogDir))
             {
                 Directory.CreateDirectory(_baseLogDir);
             }
             if (!Directory.Exists(_baseLogDir + _StateLogDir))
             {
                 Directory.CreateDirectory(_baseLogDir + _StateLogDir);
             }
             if (!Directory.Exists(_baseLogDir + _ReqestLogDir))
             {
                 Directory.CreateDirectory(_baseLogDir + _ReqestLogDir);
             }
             if (!Directory.Exists(_baseLogDir + _SendLogDir))
             {
                 Directory.CreateDirectory(_baseLogDir + _SendLogDir);
             }
             if (m_isRedirect)
             {
                 LoadServerList();
             }
         }
         public void LoadServerList()
         {
             if (File.Exists(_ServerOptionFolder + _ServerListFile))
             {
                 Stream LoadFileStream = File.OpenRead(_ServerOptionFolder + _ServerListFile);
                 StreamReader sr = new StreamReader(LoadFileStream);
                 List<ServersList> tmp = new List<ServersList>(0);
                 while (!sr.EndOfStream)
                 {
                     string line = (sr.ReadLine());
                     string[] data = line.Split(":".ToCharArray());
                     int port = 0;
                     if (int.TryParse(data[2], out port))
                     {
                         tmp.Add(new ServersList(data[0], data[1], port,false));
                     }
                 }
                 LoadFileStream.Close();
                 m_serverList = tmp.ToArray();
             }
             else
             {
                 SaveServerList();
             }
         }
         public void SaveServerList()
         {
             if (m_isRedirect)
             {


                 Stream SaveFileStream = File.OpenWrite(_ServerOptionFolder + _ServerListFile);
                 StreamWriter sr = new StreamWriter(SaveFileStream);
                 if (m_serverList!=null)
                 {
                     for (int i = 0; i < m_serverList.Length; i++)
                 {
                     sr.WriteLine(m_serverList[i].ServerName + ":" + m_serverList[i].IpServer + ":" + m_serverList[i].PortServer);

                 }
                 }
                 
                 SaveFileStream.Close();
             }

         }
         public void FormClose()
         {
            if (m_change)
             {
                 m_change = false;
                 if (m_offerOptionFile != null)
                 {
                     SaveServerList();
                     Save(m_offerOptionFile);

                 }
                 else
                 {
                     SaveServerList();
                     Save();
                 }
             }
         }
         public void ShowForm()
         {
            SetupOption form;
            form = new SetupOption();
             form.Options = this;
             //form.Visible = true;
            // form.ShowDialog();
             
             
            Thread t = new Thread(runForm);          
             t.Start(form);
             
         }
         void runForm(object obj)
         {
             Application.Run((Form)obj);
         }

         public void Save(string FileName)
         {
             if (Directory.Exists(_ServerOptionFolder))
             {
                 Stream SaveFileStream = File.Create(_ServerOptionFolder + FileName);
                 BinaryFormatter serializer = new BinaryFormatter();
                 serializer.Serialize(SaveFileStream, this);
                 SaveFileStream.Close();
                 SaveServerList();
             }
             else
             {
                 Directory.CreateDirectory(_ServerOptionFolder);
                 Stream SaveFileStream = File.Create(_ServerOptionFolder + FileName);
                 BinaryFormatter serializer = new BinaryFormatter();
                 serializer.Serialize(SaveFileStream, this);
                 SaveFileStream.Close();
                 SaveServerList();
             }
         }
         public void Save()
         {
             Save(_ServerOptionFile);
         }
         
         #endregion
        #region Static Methods

         public static ServerOptions Load(string FileName)
         {

             if (Directory.Exists(_ServerOptionFolder))
             {
                 if (File.Exists(_ServerOptionFolder + FileName))
                 {
                     Stream LoadFileStream = File.OpenRead(_ServerOptionFolder + FileName);
                     BinaryFormatter deserializer = new BinaryFormatter();
                     ServerOptions serverOptoins = (ServerOptions)deserializer.Deserialize(LoadFileStream);
                     serverOptoins.OfferOptionFile = FileName;
                     LoadFileStream.Close();
                     serverOptoins.Init();
                     return serverOptoins;
                 }
                 else
                 {
                     ServerOptions serverOptoins = new ServerOptions();
                     serverOptoins.OfferOptionFile = FileName;
                     serverOptoins.Save(FileName);
                     // serverOptoins.Init();
                     return serverOptoins;
                 }
             }
             else
             {
                 Directory.CreateDirectory(_ServerOptionFolder);
                 ServerOptions serverOptoins = new ServerOptions();
                 serverOptoins.OfferOptionFile = FileName;
                 serverOptoins.Save(FileName);
                 //serverOptoins.Init();
                 return serverOptoins;
             }

         }
         public static ServerOptions Load()
         {
             string FileName = _ServerOptionFile;
             return Load(FileName);
         }
        
         #endregion
    }
}
